package com.whoimi.admin.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
//import com.fasterxml.jackson.core.type.TypeReference;
//import com.fasterxml.jackson.databind.ObjectMapper;
import com.whoimi.admin.constant.SystemConstants;
import com.whoimi.admin.converter.MenuConverter;
import com.whoimi.admin.entity.KeyValue;
import com.whoimi.admin.entity.Menu;
import com.whoimi.admin.entity.form.MenuForm;
import com.whoimi.admin.entity.vo.MenuVO;
import com.whoimi.admin.entity.vo.RouteVO;
import com.whoimi.admin.model.Option;
import com.whoimi.admin.repository.MenuRepository;
import com.whoimi.admin.service.MenuService;
import com.whoimi.admin.unums.MenuTypeEnum;
import com.whoimi.admin.unums.StatusEnum;
import com.whoimi.common.BusiException;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import tools.jackson.core.type.TypeReference;
import tools.jackson.databind.json.JsonMapper;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

/**
 * @author whoimi
 * @since 2025-07-25
 **/
@Service
public class MenuServiceImpl implements MenuService {
    @Resource
    private MenuConverter menuConverter;

    @Resource
    private MenuRepository menuRepository;

    @Resource
    JsonMapper jsonMapper;

    @Override
    public List<RouteVO> getCurrentUserRoutes(String username) {

        Set<String> roleCodes = Collections.singleton("ADMIN");

        if (CollectionUtil.isEmpty(roleCodes)) {
            return Collections.emptyList();
        }
        List<Menu> menuList = List.of();
        if ("admin".equals(username)) {
            menuList = menuRepository.findByTypeNotContainingOrderBySort(MenuTypeEnum.BUTTON.getValue());
        }
//        else {
//            menuList = this.baseMapper.getMenusByRoleCodes(roleCodes);
//        }
        return buildRoutes(SystemConstants.ROOT_NODE_ID, menuList);
    }

    private List<RouteVO> buildRoutes(Long parentId, List<Menu> menuList) {
        List<RouteVO> routeList = new ArrayList<>();

        for (Menu menu : menuList) {
            if (menu.getParentId().equals(parentId)) {
                RouteVO routeVO = toRouteVo(menu);
                List<RouteVO> children = buildRoutes(menu.getId(), menuList);
                if (!children.isEmpty()) {
                    routeVO.setChildren(children);
                }
                routeList.add(routeVO);
            }
        }

        return routeList;
    }

    private RouteVO toRouteVo(Menu menu) {
        RouteVO routeVO = new RouteVO();
        // 获取路由名称
        String routeName = menu.getRouteName();
        if (StrUtil.isBlank(routeName)) {
            // 路由 name 需要驼峰，首字母大写
            routeName = StringUtils.capitalize(StrUtil.toCamelCase(menu.getRoutePath(), '-'));
        }
        // 根据name路由跳转 this.$router.push({name:xxx})
        routeVO.setName(routeName);

        // 根据path路由跳转 this.$router.push({path:xxx})
        routeVO.setPath(menu.getRoutePath());
        routeVO.setRedirect(menu.getRedirect());
        routeVO.setComponent(menu.getComponent());

        RouteVO.Meta meta = new RouteVO.Meta();
        meta.setTitle(menu.getName());
        meta.setIcon(menu.getIcon());
        meta.setHidden(StatusEnum.DISABLE.getValue().equals(menu.getVisible()));
        // 【菜单】是否开启页面缓存
        if (MenuTypeEnum.MENU.getValue().equals(menu.getType())
                && ObjectUtil.equals(menu.getKeepAlive(), 1)) {
            meta.setKeepAlive(true);
        }
        meta.setAlwaysShow(ObjectUtil.equals(menu.getAlwaysShow(), 1));

        String paramsJson = menu.getParams();
        // 将 JSON 字符串转换为 Map<String, String>
        if (StrUtil.isNotBlank(paramsJson)) {
            try {
                Map<String, String> paramMap = jsonMapper.readValue(paramsJson, new TypeReference<>() {
                });
                meta.setParams(paramMap);
            } catch (Exception e) {
                throw new RuntimeException("解析参数失败", e);
            }
        }
        routeVO.setMeta(meta);
        return routeVO;
    }

    @Override
    public List<MenuVO> listMenus() {
        Iterable<Menu> menus = menuRepository.findAll();

        Set<Long> menuIds = StreamSupport.stream(menus.spliterator(), false)
                .map(Menu::getId)
                .collect(Collectors.toSet());
        // 获取所有菜单ID


        // 获取所有父级ID
        Set<Long> parentIds = StreamSupport.stream(menus.spliterator(), false)
                .map(Menu::getParentId)
                .collect(Collectors.toSet());

        // 获取根节点ID（递归的起点），即父节点ID中不包含在部门ID中的节点，注意这里不能拿顶级菜单 O 作为根节点，因为菜单筛选的时候 O 会被过滤掉
        List<Long> rootIds = parentIds.stream()
                .filter(id -> !menuIds.contains(id))
                .toList();

        // 使用递归函数来构建菜单树
        return rootIds.stream()
                .flatMap(rootId -> buildMenuTree(rootId, menus).stream())
                .collect(Collectors.toList());
    }

    /**
     * 递归生成菜单列表
     *
     * @param parentId 父级ID
     * @param menuList 菜单列表
     * @return 菜单列表
     */
    private List<MenuVO> buildMenuTree(Long parentId, Iterable<Menu> menuList) {
        return StreamSupport.stream(menuList.spliterator(), false)
                .filter(menu -> menu.getParentId().equals(parentId))
                .map(entity -> {
                    MenuVO menuVO = menuConverter.toVo(entity);
                    List<MenuVO> children = buildMenuTree(entity.getId(), menuList);
                    menuVO.setChildren(children);
                    return menuVO;
                }).toList();
    }

    @Override
    public void saveMenu(MenuForm menuForm) {

        Integer menuType = menuForm.getType();

        if (MenuTypeEnum.CATALOG.getValue().equals(menuType)) {  // 如果是目录
            String path = menuForm.getRoutePath();
            if (menuForm.getParentId() == 0 && !path.startsWith("/")) {
                menuForm.setRoutePath("/" + path); // 一级目录需以 / 开头
            }
            menuForm.setComponent("Layout");
        } else if (MenuTypeEnum.EXTLINK.getValue().equals(menuType)) {
            // 外链菜单组件设置为 null
            menuForm.setComponent(null);
        }
        if (Objects.equals(menuForm.getParentId(), menuForm.getId())) {
            throw new RuntimeException("父级菜单不能为当前菜单");
        }
        Menu entity = menuConverter.toEntity(menuForm);
        String treePath = generateMenuTreePath(menuForm.getParentId());
        entity.setTreePath(treePath);

        List<KeyValue> params = menuForm.getParams();
        // 路由参数 [{key:"id",value:"1"}，{key:"name",value:"张三"}] 转换为 [{"id":"1"},{"name":"张三"}]
        if (CollectionUtil.isNotEmpty(params)) {
            entity.setParams(JSONUtil.toJsonStr(params.stream()
                    .collect(Collectors.toMap(KeyValue::getKey, KeyValue::getValue))));
        } else {
            entity.setParams(null);
        }
        // 新增类型为菜单时候 路由名称唯一
        if (MenuTypeEnum.MENU.getValue().equals(menuType)) {
            Long id = menuForm.getId();
            if (id == null) {
                String routeName = menuForm.getRouteName();
                List<Menu> allByRouteName = menuRepository.findAllByRouteName(routeName);
                if (!allByRouteName.isEmpty()) {
                    throw new BusiException("routeName exits!" + routeName);
                }
            }
        } else {
            // 其他类型时 给路由名称赋值为空
            entity.setRouteName(null);
        }
        Menu save = menuRepository.save(entity);
//        boolean result = this.saveOrUpdate(entity);
//        if (result) {
//            // 编辑刷新角色权限缓存
//            if (menuForm.getId() != null) {
//                roleMenuService.refreshRolePermsCache();
//            }
//        }
        // 修改菜单如果有子菜单，则更新子菜单的树路径
        updateChildrenTreePath(entity.getId(), treePath);
    }

    @Override
    public List<Option<Long>> listMenuOptions(boolean onlyParent) {
        List<Menu> menuList = menuRepository.findAllByOrderBySort();
        if (onlyParent) {
            menuList = menuList.stream().filter(menu -> menu.getType().equals(MenuTypeEnum.CATALOG.getValue()) || menu.getType().equals(MenuTypeEnum.MENU.getValue())).toList();
        }

        return buildMenuOptions(SystemConstants.ROOT_NODE_ID, menuList);
    }

    @Override
    public MenuForm getMenuForm(Long id) {
        Menu entity = menuRepository.findById(id).orElseThrow(() -> new BusiException("getMenuForm id " + id + " not found"));
        MenuForm formData = menuConverter.toForm(entity);
        // 路由参数字符串 {"id":"1","name":"张三"} 转换为 [{key:"id", value:"1"}, {key:"name", value:"张三"}]
        String params = entity.getParams();
        if (StrUtil.isNotBlank(params)) {
            try {
                // 解析 JSON 字符串为 Map<String, String>
                Map<String, String> paramMap = jsonMapper.readValue(params, new TypeReference<>() {
                });

                // 转换为 List<KeyValue> 格式 [{key:"id", value:"1"}, {key:"name", value:"张三"}]
                List<KeyValue> transformedList = paramMap.entrySet().stream()
                        .map(entry -> new KeyValue(entry.getKey(), entry.getValue()))
                        .toList();

                // 将转换后的列表存入 MenuForm
                formData.setParams(transformedList);
            } catch (Exception e) {
                throw new RuntimeException("解析参数失败", e);
            }
        }

        return formData;
    }

    /**
     * 递归生成菜单下拉层级列表
     *
     * @param parentId 父级ID
     * @param menuList 菜单列表
     * @return 菜单下拉列表
     */
    private List<Option<Long>> buildMenuOptions(Long parentId, List<Menu> menuList) {
        List<Option<Long>> menuOptions = new ArrayList<>();

        for (Menu menu : menuList) {
            if (menu.getParentId().equals(parentId)) {
                Option<Long> option = new Option<>(menu.getId(), menu.getName());
                List<Option<Long>> subMenuOptions = buildMenuOptions(menu.getId(), menuList);
                if (!subMenuOptions.isEmpty()) {
                    option.setChildren(subMenuOptions);
                }
                menuOptions.add(option);
            }
        }

        return menuOptions;
    }

    /**
     * 部门路径生成
     *
     * @param parentId 父ID
     * @return 父节点路径以英文逗号(, )分割，eg: 1,2,3
     */
    private String generateMenuTreePath(Long parentId) {
        if (SystemConstants.ROOT_NODE_ID.equals(parentId)) {
            return String.valueOf(parentId);
        } else {
            Menu parent = menuRepository.findById(parentId).orElseThrow(() -> new BusiException("父级菜单不存在" + parentId));
            return parent != null ? parent.getTreePath() + "," + parent.getId() : null;
        }
    }

    /**
     * 更新子菜单树路径
     *
     * @param id       当前菜单ID
     * @param treePath 当前菜单树路径
     */
    private void updateChildrenTreePath(Long id, String treePath) {
        List<Menu> children = menuRepository.findAllByParentId(id);
        if (CollectionUtil.isNotEmpty(children)) {
            // 子菜单的树路径等于父菜单的树路径加上父菜单ID
            String childTreePath = treePath + "," + id;
            menuRepository.updateTreePathByParentId(childTreePath, id);
            for (Menu child : children) {
                // 递归更新子菜单
                updateChildrenTreePath(child.getId(), childTreePath);
            }
        }
    }
}
